/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package za.co.pas.business.data;

import java.io.Serializable;
import java.util.Calendar;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne;
import javax.persistence.OneToOne;
import javax.persistence.Transient;
import za.co.pas.business.constant.Constant;
import za.co.pas.business.data.audit.UserLoginDetails_AUDIT;

/**
 *
 * @author alabuschagne
 */
@Entity
public class UserLoginDetails implements Serializable
{
    //Don't check company!

    private List<Company> companies = new LinkedList<Company>();
    private static final long serialVersionUID = 1L;
    private Long id;
    private String userName = "";
    private String password = "";
    private UserType userType;
    private Person contactPerson;
    private Boolean enabled = Boolean.TRUE;
    private boolean processed = false;
    private UserCompanyGroup userGroup;
    //
    private Company loggedInCompany;
    private List<UserLoginDetails_AUDIT> userAuditList = new LinkedList<UserLoginDetails_AUDIT>();

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    public Long getId()
    {
        return id;
    }

    public void setId(Long id)
    {
        this.id = id;
    }

    @Override
    public int hashCode()
    {
        int hash = 0;
        hash += (id != null ? id.hashCode() : 0);
        return hash;
    }

    @Override
    public boolean equals(Object object)
    {
        // TODO: Warning - this method won't work in the case the id fields are not set
        if (!(object instanceof UserLoginDetails))
        {
            return false;
        }
        UserLoginDetails other = (UserLoginDetails) object;
        if ((this.id == null && other.id != null) || (this.id != null && !this.id.equals(other.id)))
        {
            return false;
        }
        return true;
    }

    @Override
    public String toString()
    {
        return getUserName();
    }

    /**
     * @return the userName
     */
    public String getUserName()
    {
        return userName;
    }

    /**
     * @param userName the userName to set
     */
    public void setUserName(String userName)
    {
        this.userName = userName;
    }

    /**
     * @return the password
     */
    public String getPassword()
    {
        return password;
    }

    /**
     * @param password the password to set
     */
    public void setPassword(String password)
    {
        this.password = password;
    }

    /**
     * @return the userType
     */
    @ManyToOne(cascade = CascadeType.ALL)
    public UserType getUserType()
    {
        return userType;
    }

    /**
     * @param userType the userType to set
     */
    public void setUserType(UserType userType)
    {
        this.userType = userType;
    }

    @ManyToMany(cascade = CascadeType.ALL)
    public List<Company> getCompanies()
    {
        return companies;
    }

    public void setCompanies(List<Company> companies)
    {
        this.companies = companies;
    }

    /**
     * @return the contactPerson
     */
    @OneToOne(cascade = CascadeType.ALL)
    public Person getContactPerson()
    {
        return contactPerson;
    }

    /**
     * @param contactPerson the contactPerson to set
     */
    public void setContactPerson(Person contactPerson)
    {
        this.contactPerson = contactPerson;
    }

    /**
     * @return the enabled
     */
    public Boolean getEnabled()
    {
        return enabled;
    }

    /**
     * @param enabled the enabled to set
     */
    public void setEnabled(Boolean enabled)
    {
        this.enabled = enabled;
    }

    public boolean check(UserLoginDetails otherUser)
    {
        if (otherUser == null)
        {
            return false;
        }
        if (userName.compareTo(otherUser.getUserName()) != 0)
        {
            return false;
        }
        else if (password.compareTo(otherUser.getPassword()) != 0)
        {
            return false;
        }
        else if (enabled.compareTo(otherUser.getEnabled()) != 0)
        {
            return false;
        }
        else if ((userType == null) && (otherUser.getUserType() != null))
        {
            return false;
        }
        else if ((userType != null) && (!userType.check(otherUser.getUserType())))
        {
            return false;
        }
        else if ((contactPerson == null) && (otherUser.getContactPerson() != null))
        {
            return false;
        }
        else if ((contactPerson != null) && (!contactPerson.check(otherUser.getContactPerson())))
        {
            return false;
        }
        return true;
    }

    @Override
    public UserLoginDetails clone()
    {
        UserLoginDetails uld = new UserLoginDetails();
        uld.setContactPerson(contactPerson.clone());
        uld.setEnabled(enabled);
        uld.setId(id);
        uld.setPassword(password);
        uld.setUserName(userName);
        uld.setUserType(userType.clone());
        uld.setUserGroup(userGroup);
        return uld;
    }

    @Transient
    public boolean isProcessed()
    {
        return processed;
    }

    /**
     * @param processed the processed to set
     */
    public void setProcessed(boolean processed)
    {
        this.processed = processed;
    }

    /**
     * @return the userGroup
     */
    @ManyToOne(cascade = CascadeType.ALL)
    public UserCompanyGroup getUserGroup()
    {
        return userGroup;
    }

    /**
     * @param userGroup the userGroup to set
     */
    public void setUserGroup(UserCompanyGroup userGroup)
    {
        this.userGroup = userGroup;
    }

    public void add(Company company)
    {
        if (companies == null)
        {
            companies = new LinkedList<Company>();
        }
        companies.add(company);
    }

    public void setLoggedInCompany(Company comp)
    {
        loggedInCompany = comp;
    }

    /**
     * @return the loggedInCompany
     */
    @Transient
    public Company getLoggedInCompany()
    {
        return loggedInCompany;
    }

    private void makeAudit(Company company, String colName, UserLoginDetails uld, Object oldValue, Object newValue)
    {
        UserLoginDetails_AUDIT ca = new UserLoginDetails_AUDIT();
        ca.setColName(colName);
        ca.setChangedAt(Calendar.getInstance());
        ca.setChangedBy(uld);
        if (getId() != null)
        {
            ca.setCompany(company);
        }
        else
        {
            ca.setCompany(null);//new
        }
        ca.setLongId(getId());
        if (newValue != null)
        {
            ca.setNewValue(newValue.toString());
        }
        else
        {
            ca.setNewValue(null);
        }

        if (oldValue != null)
        {
            ca.setOldValue(oldValue.toString());
        }
        else
        {
            ca.setOldValue(null);
        }
        add(ca);
    }

    public boolean set(Company company, UserLoginDetails uld, UserLoginDetails uN, boolean updateCompany)
    {
        boolean updated = false;
        if (uN == null)
        {
            return updated;
        }
        if (!Constant.booleanCompare(getEnabled(), uN.getEnabled()))
        {
            makeAudit(company, "ENABLED", uld, getEnabled(), uN.getEnabled());
            setEnabled(uN.getEnabled());
            updated = true;
        }
        if (!Constant.stringCompare(getPassword(), uN.getPassword()))
        {
            makeAudit(company, "PASSWORD", uld, getPassword(), uN.getPassword());
            setPassword(uN.getPassword());
            updated = true;
        }
        boolean update = false;
        if ((getUserGroup() == null) && (uN.getUserGroup() != null))
        {
            update = true;
        }
        else if ((getUserGroup() != null) && (uN.getUserGroup() != null))
        {
            update = !getUserGroup().check(uN.getUserGroup());
        }
        else if ((getUserGroup() != null) && (uN.getUserGroup() == null))
        {
            update = true;
        }
        if (update)
        {
            makeAudit(company, "USERGROUP", uld, getUserGroup(), uN.getUserGroup());
            setUserGroup(uN.getUserGroup());
            updated = true;
        }
        if (!Constant.stringCompare(getUserName(), uN.getUserName()))
        {
            makeAudit(company, "USERNAME", uld, getUserName(), uN.getUserName());
            setUserName(uN.getUserName());
            updated = true;
        }
        update = false;
        if ((getUserType() == null) && (uN.getUserType() != null))
        {
            update = true;
        }
        else if ((getUserType() != null) && (uN.getUserType() != null))
        {
            update = !getUserType().check(uN.getUserType());
        }
        else if ((getUserType() != null) && (uN.getUserType() == null))
        {
            update = true;
        }
        if (update)
        {
            makeAudit(company, "USERTYPE", uld, getUserType(), uN.getUserType());
            setUserType(uN.getUserType());
            updated = true;
        }

        update = false;
        if ((getContactPerson() == null) && (uN.getContactPerson() != null))
        {
            update = true;
        }
        else if ((getContactPerson() != null) && (uN.getContactPerson() != null))
        {
            update = !getContactPerson().check(uN.getContactPerson());
        }
        else if ((getContactPerson() != null) && (uN.getContactPerson() == null))
        {
            update = true;
        }
        if (update)
        {
            //setUserType(uN.getContactPerson());
            if (getContactPerson() != null)
            {
                updated |= getContactPerson().set(company, uld, uN.getContactPerson());
            }
            else
            {
                makeAudit(company, "CONTACTPERSON", uld, getContactPerson(), uN.getContactPerson());
                setContactPerson(uN.getContactPerson());
                updated = true;
            }
        }

        if (updateCompany)
        {
            //Set all processed false
            if (uN.getCompanies() != null)
            {
                ListIterator<Company> itN = uN.getCompanies().listIterator();
                while (itN.hasNext())
                {
                    Company cN = itN.next();
                    cN.setProcessed(false);
                }
            }
            List<Company> cmps = getCompanies();
            if (cmps == null)
            {
                cmps = new LinkedList<Company>();
            }
            ListIterator<Company> it = cmps.listIterator();

            while (it.hasNext())
            {
                Company c = it.next();
                c.setProcessed(false);
                if (uN.getCompanies() != null)
                {
                    ListIterator<Company> itN = uN.getCompanies().listIterator();
                    while (itN.hasNext())
                    {
                        Company cN = itN.next();
                        if (c.getId() == cN.getId())
                        {
                            c = cN;//???
                            updated = true;
                            c.setProcessed(true);
                            cN.setProcessed(true);
                            break;//out of inner loop
                        }
                    }
                }
            }
            //if it is in the old list but not in the new list, then remove it from this list
            it = cmps.listIterator();
            while (it.hasNext())
            {
                Company c = it.next();
                if (!c.isProcessed())
                {
                    //Remove user from this company
                    cmps.remove(c);
                    //Remove company from user
                    c.removeUser(this);
                    updated = true;
                }
            }
            //if it is in the new list but not in the old list, then add it
            it = uN.getCompanies().listIterator();
            while (it.hasNext())
            {
                Company c = it.next();
                if (!c.isProcessed())
                {
                    cmps.add(c);
                    c.add(this);
                    updated = true;
                }
            }
        }
        return updated;
    }

    /**
     * @return the addressAuditList
     */
    @Transient
    public List<UserLoginDetails_AUDIT> getUserAuditList()
    {
        return userAuditList;
    }

    /**
     * @param addressAuditList the addressAuditList to set
     */
    public void setUserAuditList(List<UserLoginDetails_AUDIT> userAuditList)
    {
        this.userAuditList = userAuditList;
    }

    private void add(UserLoginDetails_AUDIT ca)
    {
        if (userAuditList == null)
        {
            userAuditList = new LinkedList<UserLoginDetails_AUDIT>();
        }
        userAuditList.add(ca);
    }

    void removeCompany(Company aThis)
    {
        if (companies != null)
        {
            ListIterator<Company> it = this.companies.listIterator();
            while (it.hasNext())
            {
                Company c = it.next();
                if (aThis.getId() == c.getId())
                {
                    companies.remove(c);
                    break;//Out of loop
                }
            }
        }
    }

    public String logPrint(int level)
    {
        StringBuilder tab = new StringBuilder();
        for(int i = 0; i < level; i++)
        {
            tab.append("\t");
        }
        StringBuilder sb = new StringBuilder(tab.toString());
        sb.append("USER\n");
        sb.append(tab.toString());
        sb.append("ID: \t");
        sb.append(id);
        sb.append("\n");
        sb.append(tab.toString());
        sb.append("UserName: \t");
        sb.append(userName);
        sb.append("\n");
        sb.append(tab.toString());
        sb.append("Password: \t");
        sb.append(password);
        sb.append("\n");
        sb.append(tab.toString());
        sb.append("Enabled: \t");
        sb.append(enabled);
        sb.append("\n");
        sb.append(tab.toString());
        sb.append("UserType: \t");
        int l2 = level + 1;
        if(userType != null)
        {
            sb.append(userType.logPrint(l2));
        }
        else
        {
            sb.append("null");
        }
        sb.append("\n");
        sb.append(tab.toString());
        sb.append("UserGroup: \t");
        if(userGroup != null)
        {
            sb.append(userGroup.logPrint(l2));
        }
        else
        {
            sb.append("null");
        }
        sb.append("\n");
        sb.append(tab.toString());
        sb.append("ContactPerson: \t");
        if(contactPerson != null)
        {
            sb.append(contactPerson.logPrint(l2));
        }
        else
        {
            sb.append("null");
        }
        return sb.toString();
    }
}
